
#include <BFont>
#include <BFile>
#include "IGlobal.h"
#include "IFontFamily.h"
#include "member_BFont.h"

using namespace BWE;

BMap<BString, FontFamilyHolder>& FontFamilyMap()
{
	static BMap<BString, FontFamilyHolder> familyMap;
	return familyMap;
}

member_BFont::member_BFont(BFont* font)
{
	boss = font;
	bold = false;
	italic = false;
	underline = false;
	spaceSize = -1;
	tabSize = -1;
	encoding = Encoding_None;
}
member_BFont::~member_BFont()
{

}

bool member_BFont::loadFamily()
{
	auto& familyMap = FontFamilyMap();
	IFontFamily* font_family = familyMap(family);
	if (font_family)
	{
		fontFamily = font_family;
		encoding = fontFamily->encodingList.first();
		return true;
	}

	BString fontFileName;
	for (int i = 0; i < app_fontPaths.size(); i++)
	{
		BString fileName = app_fontPaths[i];
		fileName << '/' << family << ".ttf";
		if (BFile::Exist(fileName))
		{
			fontFileName = fileName;
			break;
		}
		else
		{
			fileName.replace(".ttf", ".ttc");
			if (BFile::Exist(fileName))
			{
				fontFileName = fileName;
				break;
			}
		}
	}

	if (fontFileName.empty())
	{
		BString fileName("./font");
		fileName << '/' << family << ".ttf";
		if (BFile::Exist(fileName))
		{
			fontFileName = fileName;
		}
		else
		{
			fileName.replace(".ttf", ".ttc");
			if (BFile::Exist(fileName))
			{
				fontFileName = fileName;
			}
		}
	}

	if (fontFileName.empty())
	{
		BString fileName = app_libPath;
		fileName << "/font/" << family << ".ttf";
		if (BFile::Exist(fileName))
		{
			fontFileName = fileName;
		}
		else
		{
			fileName.replace(".ttf", ".ttc");
			if (BFile::Exist(fileName))
			{
				fontFileName = fileName;
			}
		}
	}

	if (fontFileName.empty())
	{

#ifdef _WIN32
		BString fileName("C:/Windows/Fonts/");
#endif
#ifdef linux
		BString fileName("/usr/share/fonts");
#endif
		fileName << family << ".ttf";
		if (BFile::Exist(fileName))
		{
			fontFileName = fileName;
		}
		else
		{
			fileName.replace(".ttf", ".ttc");
			if (BFile::Exist(fileName))
			{
				fontFileName = fileName;
			}
		}
	}

	if (fontFileName.empty())
		return false;

	fontFamily = new IFontFamily(fontFileName);
	familyMap[family] = fontFamily;
	encoding = fontFamily->encodingList.first();
	return true;
}

CodeInfo* member_BFont::getCodeInfo(const BCode& code)
{
	//if (code == 13)
	//	code = 164;

	if (!fontFamily)
		return 0;

	if (troubleCodes.contain(code))
		return 0;

	auto it = table.find(code);
	if (it.valid())
		return &(*it);

	CodeInfo& info = table[code];

	FT_ULong ftcode = 0;
	if (code.num() == 1)
	{
		ftcode = code;
	}
	else if (code.num() == 2)
	{
		if (encoding == Encoding_Unicode)
			ftcode = GB2312_To_UTF8(code);
		else
		{
			const char* str = code.str();
			char* ptr = (char*)&ftcode;
			ptr[0] = str[1];
			ptr[1] = str[0];
			ptr[2] = 0;
			ptr[3] = 0;
		}
	}
	else if (code.num() == 3)
	{
		if (encoding == Encoding_GB2312)
			ftcode = UTF8_To_GB2312(code);
		else
		{
			const unsigned char* str = (const unsigned char*)code.str();
			int va = str[2];
			int vb = str[1];
			int vc = str[0];
			va = va & 0x3f;
			vb = vb & 0x3f;
			vc = vc & 0x1f;
			vb = vb << 6;
			vc = vc << 12;
			ftcode = va + vb + vc;
		}
	}
	else if (code.num() == 4)
	{
		if (encoding == Encoding_GB2312)
			ftcode = UTF8_To_GB2312(code);
		else
		{
			const unsigned char* str = (const unsigned char*)code.str();
			int va = str[3];
			int vb = str[2];
			int vc = str[1];
			int vd = str[0];
			va = va & 0x3f;
			vb = vb & 0x3f;
			vc = vc & 0x3f;
			vd = vc & 0x1f;
			vb = vb << 6;
			vc = vc << 12;
			vd = vd << 18;
			ftcode = va + vb + vc + vd;
		}
	}

	if (!fontFamily->image(ftcode, size, info))
		troubleCodes.append(code);

	return &info;
}

BSize member_BFont::codeSize(const BCode& code)
{
	if (code == '\n')
		return BSize(size, size);

	if (code == ' ')
	{
		if(spaceSize > 0)
			return BSize(spaceSize, size);
		return BSize(size / 2, size);
	}

	if(code == '\t')
	{
		if (tabSize > 0)
			return BSize(tabSize, size);
		return BSize(size, size);
	}

	CodeInfo* info = getCodeInfo(code);
	if (!info)
		return BSize(size, size);

	const BImage* image = info->image.ptr();
	if (!image)
		return BSize(size, size);

	int width = info->left + image->width();

	return BSize(width, size);
}
